#include "CRenderTargetOGL.h"
#include "CCamera.h"
#include "CRendererOGL.h"
#include "CRenderQueueSorter.h"
#include "IRenderable.h"
#include "DataManager.h"
#include "IVertexBuffer.h"
#include "IEffect.h"

/// The default Render Target Constructor refers to the OpenGL Back-Buffer, and renders directly to it
CRenderTargetOGL::CRenderTargetOGL( int width, int height )
	:	IRenderTarget( width, height, NULL, JUST_DONT, JUST_DONT, eDBF_DEFAULT_SETTINGS ),
		m_uiFrameBufferHandleOGL( 0 ),
		m_uiTextureHandleOGL( 0 ),
		m_uiRenderBufferDepthHandleOGL( 0 ) {

	#ifndef TZM_FORBID_RENDERTARGETS
		// Unbind all
		glBindFramebufferEXT	( GL_FRAMEBUFFER_EXT, 	0 );
		glBindRenderbufferEXT( GL_RENDERBUFFER_EXT, 	0 );
	#endif
	glBindTexture			( GL_TEXTURE_2D, 			0 );

	m_RenderQueue = new CRenderQueueSorter( );

	// Set the opengl viewport
	glViewport( 0, 0, width, height );

	// Clear the screen
	Clear( BLACK );

	sCameraData perspective;
	perspective.farplane 	= 1024;
	perspective.fieldofview = 75;
	perspective.nearplane 	= 0.1;
	perspective.viewport[2] = width; perspective.viewport[3] = height;
	perspective.orthogonal 	= false;
	SetPerspective( perspective );

	m_pCamera = new CCamera( perspective );

	SetTransform( m_pCamera );
}

/// Create off-screen Render Target with custom color and depth format. Supports DEPTH24, DEPTH, even RGBA16F for color (for HDR)
/**	@param w - width of the render target in pixels
		@param h - height of the render target in pixels
		@param data - preloaded pixel data to copy
		@param color_format - format of the data inside the color texture. Can be eTF_RGBA32, eTF_RGB24, eTF_X8, eTF_RGBA16F, etc.
		@param depth_format - format of the depth component. Can be eTF_DEPTH, eTF_DEPTH24, etc.
		@param flags - render target usage flags */
CRenderTargetOGL::CRenderTargetOGL( int w, int h, byte* data, int color_format, int depth_format, int flags )
	:	IRenderTarget( w, h, data, color_format, depth_format, flags ) {

	#ifdef TZM_FORBID_RENDERTARGETS
		glBindTexture			( GL_TEXTURE_2D, 			0 );

		m_RenderQueue = new CRenderQueueSorter( );

		// Set the opengl viewport
		glViewport( 0, 0, w, h );

		// Clear the screen
		Clear( BLACK );

		sCameraData perspective;
		perspective.farplane 	= 1024;
		perspective.fieldofview = 75;
		perspective.nearplane 	= 0.1;
		perspective.viewport[2] = w; perspective.viewport[3] = h;
		perspective.orthogonal 	= false;
		SetPerspective( perspective );

		m_pCamera = new CCamera( perspective );

		SetTransform( m_pCamera );
		return;
	#else

	if( flags == eDBF_DEFAULT_SETTINGS )
		flags = m_DefaultFlagsRenderTarget;

	if( flags & eDBF_VRAM ) {
		if( color_format ) {
			// First we generate framebuffer handle:
			glGenFramebuffersEXT( 1, &m_uiFrameBufferHandleOGL );
			// Then bind it so we can manipulate it:
			glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, m_uiFrameBufferHandleOGL );

			// Now we generate texture handle:
			glGenTextures( 1, &m_uiTextureHandleOGL );
			// Activate texture stage 0:
			glActiveTextureARB( GL_TEXTURE0 );
			// And bind the newly created texture so we can set it up:
			glBindTexture(GL_TEXTURE_2D, m_uiTextureHandleOGL );

			// Here we set it up, depending on the format:
			switch( color_format ) {
				case eTF_RGBA32:
					glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, 			w, h, 0, GL_RGBA,  GL_UNSIGNED_BYTE, data );
					break;
				case eTF_RGB24:
					glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB, 			w, h, 0, GL_RGB,   GL_UNSIGNED_BYTE, data );
					break;
				case eTF_X8:
					glTexImage2D( GL_TEXTURE_2D, 0, GL_ALPHA, 		w, h, 0, GL_ALPHA, GL_UNSIGNED_BYTE, data );
					break;
				case eTF_RGBA16F:
					glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA16F_ARB, w, h, 0, GL_ALPHA, GL_UNSIGNED_BYTE, data );
					break;
				default:
					glTexImage2D( GL_TEXTURE_2D, 0, GL_ALPHA, 		w, h, 0, GL_ALPHA, GL_UNSIGNED_BYTE, data );
					break;
			}

			// When we magnify the texture, we'll use linear interpolation of the pixels:
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
			// When we minify the texture, we'll use the nearest pixel:
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
			// The render target will always clamp to U edges:
			glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
			// The render target will always clamp to V edges:
			glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

			// At the end, we connect our texture handle to the framebuffer handle:
			glFramebufferTexture2DEXT( GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, m_uiTextureHandleOGL, 0);

			if( depth_format ) {
				// Generate renderbuffer for the depth attachment
				glGenRenderbuffersEXT( 1, &m_uiRenderBufferDepthHandleOGL );
				glBindRenderbufferEXT( GL_RENDERBUFFER_EXT, m_uiRenderBufferDepthHandleOGL );

				switch( depth_format ) {
					case eTF_DEPTH24:
						glRenderbufferStorageEXT( GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT24, w, h );
						break;
					default:
						glRenderbufferStorageEXT( GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT,   w, h );
						break;
				}

				glFramebufferRenderbufferEXT( GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, m_uiRenderBufferDepthHandleOGL );
			}
		}
		else if( depth_format ) {
			// Create framebuffer for depth only
			glGenFramebuffersEXT( 1, &m_uiFrameBufferHandleOGL );
			// And bind it so we can set it up
			glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, m_uiFrameBufferHandleOGL );

			// Create the texture we'll use for the depth
			glGenTextures( 1, &m_uiTextureHandleOGL );
			// And bind it so we can set it up
			glBindTexture( GL_TEXTURE_2D, m_uiTextureHandleOGL );

			// Now set it up...
			switch( depth_format ) {
				case eTF_DEPTH24:
					glTexImage2D( GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, w, h, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, data );
					break;
				default:
					glTexImage2D( GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT,   w, h, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, data );
					break;
			}

			// Set some parameters
			glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
			// Attach it as depth element
			glFramebufferTexture2DEXT( GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, m_uiTextureHandleOGL, 0 );
			// I dont know what this does :D
			glDrawBuffer(GL_FALSE);
			glReadBuffer(GL_FALSE);
		}

		// Unbind all
		glBindFramebufferEXT	( GL_FRAMEBUFFER_EXT, 	0 );
		glBindRenderbufferEXT( GL_RENDERBUFFER_EXT, 	0 );
		glBindTexture			( GL_TEXTURE_2D, 			0 );
	}

	// If we want it in the RAM
	if( flags & eDBF_RAM ) {
		m_RAMData = data;
	}

	m_RenderQueue = new CRenderQueueSorter( );

	Begin( );

	// Set the opengl viewport
	glViewport( 0, 0, w, h );

	// Clear the screen
	Clear( BLACK );

	sCameraData perspective;
	perspective.farplane 	= 1024;
	perspective.fieldofview = 75;
	perspective.nearplane 	= 0.1;
	perspective.viewport[2] = w; perspective.viewport[3] = h;
	perspective.orthogonal 	= false;
	SetPerspective( perspective );

	m_pCamera = new CCamera( perspective );

	SetTransform( m_pCamera );

	End( );
	#endif
}

/// Opengl Render Target Destructor
CRenderTargetOGL::~CRenderTargetOGL( ) {
	FREE( m_RenderQueue );
	FREE( m_pCamera );
	// Note: We do not free the camera overrider as it is an external instance and may fuck things a bit. So do not forget to delete it yourself if your are not using the world manager
}

/// Enqueue instanced model
/**	@param instance - the instance (position) of the model
		@param model    - renderables */
void CRenderTargetOGL::Enqueue			( IInstance* 	instance, 	IRenderable* model ) {
	m_RenderQueue->Enqueue( instance, model );
}

/// Enqueue instance with it's model reference
/**	@param instance - the instance (position) that contains valid reference to a renderable */
void CRenderTargetOGL::Enqueue			( IInstance* 	instance 	) {
	m_RenderQueue->Enqueue( instance );
}

/// Enqueue model with it's default instancing (as loaded in a scene and shown in the world)
/**	@param model - the model that contains default instance of the renderable */
void CRenderTargetOGL::Enqueue			( IRenderable* model 		) {
	m_RenderQueue->Enqueue( model );
}

/// Directly render instanced model to the render target that is currently bound
/**	@param instance - the instance (position) of the model
		@param model    - renderables */
void CRenderTargetOGL::Render				( IInstance* 	instance, 	IRenderable* model ) {
	// Set the vertex and index sources
	IVertexBuffer* geometry = NULL;
	IVertexBuffer* indices = NULL;
	if( model->GetGeometry( ) ) {
		geometry = (IVertexBuffer*) 	model->GetRepository( )->Get( model->GetGeometry( ) );
		geometry->Bind( );
	} else return;
	if( model->GetIndices( ) ) {
		indices  = (IVertexBuffer*) 	model->GetRepository( )->Get( model->GetIndices( ) );
		indices->Bind( );
	}
	// Apply effect
	if( model->GetEffect( ) ) {
		IEffect* effect 			= (IEffect*) 			model->GetRepository( )->Get( model->GetEffect( ) );
		effect->Bind( );
	}

	SetTransform( instance );
	geometry->DrawIndexed( indices );
}

/// Directly render model to the render target that is currently bound
/**	@param model    - renderable */
void CRenderTargetOGL::Render				( IRenderable* model ) {
	// Set the vertex and index sources
	IVertexBuffer* geometry = NULL;
	IVertexBuffer* indices = NULL;
	if( model->GetGeometry( ) ) {
		geometry = (IVertexBuffer*) 	model->GetRepository( )->Get( model->GetGeometry( ) );
		geometry->Bind( );
	} else return;
	if( model->GetIndices( ) ) {
		indices  = (IVertexBuffer*) 	model->GetRepository( )->Get( model->GetIndices( ) );
		indices->Bind( );
	}
	// Apply effect
	if( model->GetEffect( ) ) {
		IEffect* effect 			= (IEffect*) 			model->GetRepository( )->Get( model->GetEffect( ) );
		effect->Bind( );
	}

	//TODO, use default transformation inside the renderable
	SetTransform( NULL );
	geometry->DrawIndexed( indices );
}

/// Directly render instance to the render target that is currently bound. using the renderable that is assigned to the instance
/**	@param instance - renderable */
void CRenderTargetOGL::Render				( IInstance* 	instance ) {
	//TODO
}

/// Clear the render target with the last used clear color
void CRenderTargetOGL::Clear				( ) {
	glClear( GL_COLOR_BUFFER_BIT );
}

/// Clear the render target with the provided color. The provided color will be used from now on the clear the render target.
/**	@param color - rgba color */
void CRenderTargetOGL::Clear				( crgba &color ) {
	// Set the color that glClear() will fill the screen with
	glClearColor( color.x, color.y, color.z, color.w );
	// Clear the screen
	glClear( GL_COLOR_BUFFER_BIT );
}

/// Presents the render target on a chosen window region
/**	@param hwnd - window handle pointer */
void CRenderTargetOGL::Present			( handle hwnd ) {
	//TODO
}

/// Process the render queue. When the rendering is done, the queue will be cleared
void CRenderTargetOGL::Process			( ) {
	m_RenderQueue->Process( this );
}

/// Process the render queue. When the rendering is done, the queue will be kept as it is.
void CRenderTargetOGL::ProcessAndKeep	( ) {
	m_RenderQueue->ProcessAndKeep( this );
}

/// Clear the queue
void CRenderTargetOGL::ResetQueue		( ) {
	m_RenderQueue->Clear( );
}

/// Project a point in the 3d world to a 2d point on the screen
/**	@param point - the point to be projected in 2D
		@return the 2D point projection on the screen */
vec3r CRenderTargetOGL::Project			( cvec3r &point ) {
	//TODO
	return ORIGIN;
}

/// Returns a 3D point from a 2D screen coordinate. The 3D point is where the 2D point projects onto the far plane of projection
/**	@param point - 2D screen coordinate
		@return 3D point that lies on the far plane of projection */
vec3r CRenderTargetOGL::Unproject		( cvec3r &point ) {
	// We prepare our variables
   int  viewport[4];
	real modelview[16];
	real projection[16];
	real winX, winY;
	real farX, farY, farZ;
	real nearX, nearY, nearZ;

	// Get the needed information
	#if defined TZM_PRECISION
		glGetDoublev( GL_MODELVIEW_MATRIX, 	modelview );
		glGetDoublev( GL_PROJECTION_MATRIX, projection );
	#elif defined TZM_PERFORMANCE
		glGetFloatv( GL_MODELVIEW_MATRIX,  (float*)modelview );
		glGetFloatv( GL_PROJECTION_MATRIX, (float*)projection );
	#else
		#warning Define either TZM_PRECISION or TZM_PERFORMANCE
	#endif

	glGetIntegerv( GL_VIEWPORT, viewport );

	winX = point.x;
	winY = (real)viewport[3] - point.y;

	// Unproject
	gluUnProject( winX, winY, 0, modelview, projection, viewport, &nearX, &nearY, &nearZ);
	gluUnProject( winX, winY, 1, modelview, projection, viewport, &farX, &farY, &farZ);

   // And we are done.
   return vec3r( farX - nearX, farY - nearY, farZ - nearZ );
}

/// Returns 2D point projections from a 3D world coordinates.
/**	@param destination - this must be a valid array. Here the results will be stored
		@param points - this must be a valid array. These are the points that require projecting
		@param count - both arrays above must be of the same size and type. This is the size of these arrays. */
void 	CRenderTargetOGL::ProjectBatch	( vec3r** destination, cvec3r *points, cui32 count ) {
	//TODO
}

/// Returns 3D points from a 2D screen coordinates. The 3D points are where the 2D points project onto the far plane of projection
/**	@param destination - this must be a valid array. Here the results will be stored
		@param points - this must be a valid array. These are the points that require unprojecting
		@param count - both arrays above must be of the same size and type. This is the size of these arrays. */
void 	CRenderTargetOGL::UnprojectBatch	( vec3r** destination, cvec3r *points, cui32 count ) {
	// We prepare our variables
   int  viewport[4];
	real modelview[16];
	real projection[16];
	real winX, winY;
	real farX, farY, farZ;
	real nearX, nearY, nearZ;

	// Get the needed information
	#if defined TZM_PRECISION
		glGetDoublev( GL_MODELVIEW_MATRIX, 	modelview );
		glGetDoublev( GL_PROJECTION_MATRIX, projection );
	#elif defined TZM_PERFORMANCE
		glGetFloatv( GL_MODELVIEW_MATRIX,  (float*)modelview );
		glGetFloatv( GL_PROJECTION_MATRIX, (float*)projection );
	#else
		#warning Define either TZM_PRECISION or TZM_PERFORMANCE
	#endif

	glGetIntegerv( GL_VIEWPORT, viewport );

	for( uint i = 0; i < count; ++ i ) {
		winX = points[i].x;
		winY = (real)viewport[3] - points[i].y;

		// Unproject
		gluUnProject( winX, winY, 0, modelview, projection, viewport, &nearX, &nearY, &nearZ);
		gluUnProject( winX, winY, 1, modelview, projection, viewport, &farX, &farY, &farZ);

		*destination[i] = vec3r( farX - nearX, farY - nearY, farZ - nearZ );
	}
}

/// Set the used vertex format. This has no actual use from OpenGL
/**	@param format - the vertex format */
void CRenderTargetOGL::SetVertexFormat	( culong &format ) {

}

/// Toggle lighting on and off
/**	@param flag - true to enable lights, false to disable them */
void CRenderTargetOGL::SetStateLighting( bool flag ) {
	if( flag )
		glEnable(GL_LIGHTING);
	glDisable(GL_LIGHTING);
}

/// Toggle the culling state
/**	@param flag - culling state */
void CRenderTargetOGL::SetStateCulling	( eCULL_STATE flag ) {
	if( !flag ) {
		glDisable(GL_CULL_FACE);
		return;
	}

	glEnable(GL_CULL_FACE);

	switch( flag ) {
		case CULL_BACK:
			glCullFace(GL_BACK);
			break;
		case CULL_FRONT:
			glCullFace(GL_FRONT);
			break;
		case CULL_ALL:
			glCullFace(GL_FRONT_AND_BACK);
			break;
		default:
			glCullFace(GL_BACK);
			break;
	}
}

/// Enable or disable depth comparison
/**	@param flag - true to enable depth, false to disable depth */
void CRenderTargetOGL::SetStateDepth	( bool flag ) {
	if( flag )
		glEnable(GL_DEPTH_TEST);
	glDisable(GL_DEPTH_TEST);
}

/// Override the camera interface
/**	@param cam - set the camera overrider. If NULL, the render target will use the integrated camera */
void CRenderTargetOGL::SetCamera			( IInstance* cam ) {
	m_pCameraOverrider = cam;
}

/// Set perspective projection
/**	@param data - camera data */
void CRenderTargetOGL::SetPerspective	( const sCameraData &data ) {
	glMatrixMode( GL_PROJECTION );
	glLoadIdentity( );
	gluPerspective( data.fieldofview, ((float)data.viewport[2])/((float)data.viewport[3]), data.nearplane, data.farplane );
	glMatrixMode( GL_MODELVIEW );
}

/// Set orthogonal projection
/**	@param width - width in pixels
		@param height - height in pixels */
void CRenderTargetOGL::SetOrtho			( cint &width, cint &height ) {
	glMatrixMode( GL_PROJECTION );
	glLoadIdentity( );
	glOrtho( 0, width, height, 0, 1, -1 );
	glMatrixMode( GL_MODELVIEW );
}

/// Transform the view
/**	@param pos - position of the eye
		@param view - normalized view direction
		@param up - normalized up direction */
void CRenderTargetOGL::SetView			( cvec3r &pos, cvec3r &view, cvec3r &up ) {
   glMatrixMode( GL_MODELVIEW );
   glLoadIdentity( );
   vec3r LookAt = pos + view; // Look ahead of position

   gluLookAt(  pos.x,    pos.y,    pos.z,
               LookAt.x, LookAt.y, LookAt.z,
               up.x,     up.y,     up.z 		);
}

/// Transform the view
/**	@param camera - instance or camera interface holding 3d transformation data */
void CRenderTargetOGL::SetView			( IInstance* camera ) {
	if( !camera ) {
		if( !m_pCameraOverrider )
			SetView( m_pCamera );
		else
			SetView( m_pCameraOverrider );
		return;
	}

   glMatrixMode( GL_MODELVIEW );
   glLoadIdentity( );
   vec3r pos 	= camera->GetPosition( );
   vec3r up 	= camera->GetUpVector( );
   vec3r LookAt = pos + camera->GetViewVector( ); // Look ahead of position

   gluLookAt(  pos.x,    pos.y,    pos.z,
               LookAt.x, LookAt.y, LookAt.z,
               up.x,     up.y,     up.z 		);
}

/// Apply effect
/**	@param eff - effect pointer */
void CRenderTargetOGL::SetEffect			( IEffect* eff ) {

}

/// Transform the world
/**	@param instance - instance that holds transformation data */
void CRenderTargetOGL::SetTransform		( IInstance* instance ) {
	glMatrixMode( GL_MODELVIEW );

	if( !instance ) {
		glMultMatrixd( (double*)&(IDENTITY_MATRIX) );
		//glLoadIdentity( );
		return;
	}

	//TODO Test if right:
	#if defined TZM_PRECISION
		glMultMatrixd( (double*)&(instance->GetTransform( )) );
		vec3r scale = instance->GetScale( );
		glScaled( scale.x, scale.y, scale.z );
	#elif defined TZM_PERFORMANCE
		glMultMatrixf( (float*)&(instance->GetTransform( )) );
		vec3r scale = instance->GetScale( );
		glScalef( scale.x, scale.y, scale.z );
	#else
		#warning Define either TZM_PRECISION or TZM_PERFORMANCE
	#endif
}

/// Apply shader
/**	@param shader - shader interface */
void CRenderTargetOGL::SetShader			( IShader* shader ) {

}

/// Apply light
/**	@param i - hardware light index
		@param lightinst - 3d position and orientation of the light
		@param lightdata - the light data structure with light parameters */
void CRenderTargetOGL::SetLight			( cint i, IInstance* lightinst, 	const sLightData &lightdata ) {

}

/// Apply fog
/**	@param color - fog color
		@param mode - fog interpolation mode
		@param start - start of fog. 0.0 being the near plane and 1.0 being the far plane
		@param end - end of fog. 0.0 being the near plane and 1.0 being the far plane
		@param density - the thickness of the fog. 0.0 being fully transparent, and 1.0 being fully thick */
void CRenderTargetOGL::SetFog				( crgba &color, cint mode, creal start, creal end, creal density ) {
	switch( mode ) {
		case 1:
			glFogi( GL_FOG_MODE, GL_LINEAR );
			break;
		case 2:
			glFogi( GL_FOG_MODE, GL_EXP );
			break;
		case 3:
			glFogi( GL_FOG_MODE, GL_EXP2 );
			break;
		default:
			glFogi( GL_FOG_MODE, GL_EXP2 );
			break;
	}

	#if defined TZM_PRECISION
		float col[] = { (float)color.x, (float)color.y, (float)color.z, (float)color.w };
		glFogfv( GL_FOG_COLOR, 		col );
		glFogf ( GL_FOG_DENSITY, 	(float)density );
		glFogf ( GL_FOG_START, 		(float)start);
		glFogf ( GL_FOG_END, 		(float)end);
	#elif defined TZM_PERFORMANCE
		float col[] = { color.x, color.y, color.z, color.w };
		glFogfv( GL_FOG_COLOR, 		col );
		glFogf ( GL_FOG_DENSITY, 	density );
		glFogf ( GL_FOG_START, 		start);
		glFogf ( GL_FOG_END, 		end);
	#else
		#warning Define either TZM_PRECISION or TZM_PERFORMANCE
	#endif

   //if( quality == PER_VERTEX )
      //glHint( GL_FOG_HINT, GL_FASTEST );
   //else
		glHint( GL_FOG_HINT, GL_NICEST );
}

/// Begin using the render target. It binds the render target for rendering to it.
/// If this render target is the backbuffer, then render targets are off, after calling this function.
void CRenderTargetOGL::Begin				( ) {
	#ifndef TZM_FORBID_RENDERTARGETS
		glBindFramebufferEXT	( GL_FRAMEBUFFER_EXT, 	m_uiFrameBufferHandleOGL );
		glBindRenderbufferEXT( GL_RENDERBUFFER_EXT, 	m_uiRenderBufferDepthHandleOGL );
	#endif
}

/// Render RAM array of vertices to the screen
/**	@param type - primitive type
		@param count - number of elements in the array
		@param data - the array
		@param stride - the size of one element in the array */
void CRenderTargetOGL::RenderPrimitiveUserPointer( cuint type, cuint count, handle data, cuint stride ) {

}

/// Begin drawing primitive
/**	@param primitive_type - type of geometry primitive */
void CRenderTargetOGL::BeginPrimitive	( VERTEX_PRIMITIVE_TYPE primitive_type ) {
	switch( primitive_type ) {
		case VPT_LINES:
			glBegin( GL_LINES );
			break;
		case VPT_LINE_STRIP:
			glBegin( GL_LINE_STRIP );
			break;
		case VPT_POINTS:
			glBegin( GL_POINTS );
			break;
		case VPT_TRIANGLES:
			glBegin( GL_TRIANGLES );
			break;
		case VPT_TRI_STRIP:
			glBegin( GL_TRIANGLE_STRIP );
			break;
		case VPT_QUADS:
			glBegin( GL_QUADS );
			break;
		default:
			return;
	};
}

/// Render vertex that has only position data
/**	@param point - vertex position */
void CRenderTargetOGL::RenderVertex		( cvec3r &point ) {
	#if defined TZM_PRECISION
		glVertex3d( point.x, point.y, point.z );
	#elif defined TZM_PERFORMANCE
		glVertex3f( point.x, point.y, point.z );
	#else
		#warning Define either TZM_PRECISION or TZM_PERFORMANCE!
	#endif
}

/// Render vertex that has position and texture data
/**	@param point - vertex position
		@param uv - texture coordinates */
void CRenderTargetOGL::RenderVertex		( cvec3r &point, cvec2r &uv ) {
	#if defined TZM_PRECISION
		glVertex3d( point.x, point.y, point.z );
		glTexCoord2d( uv.x, uv.y );
	#elif defined TZM_PERFORMANCE
		glVertex3f( point.x, point.y, point.z );
		glTexCoord2f( uv.x, uv.y );
	#else
		#warning Define either TZM_PRECISION or TZM_PERFORMANCE!
	#endif
}

/// Render vertex that has position, texture coordinates, and color
/**	@param point - vertex position
		@param uv - texture coordinates
		@param color - rgba color data */
void CRenderTargetOGL::RenderVertex		( cvec3r &point, cvec2r &uv, crgba &color ) {
	#if defined TZM_PRECISION
		glVertex3d( point.x, point.y, point.z );
		glTexCoord2d( uv.x, uv.y );
		glColor4d( color.x, color.y, color.z, color.w );
	#elif defined TZM_PERFORMANCE
		glVertex3f( point.x, point.y, point.z );
		glTexCoord2f( uv.x, uv.y );
		glColor4f( color.x, color.y, color.z, color.w );
	#else
		#warning Define either TZM_PRECISION or TZM_PERFORMANCE!
	#endif
}

/// Render vertex that has position, texture coordinates, and color
/**	@param point - vertex position
		@param color - rgba color data */
void CRenderTargetOGL::RenderVertex		( cvec3r &point, crgba &color ) {
	#if defined TZM_PRECISION
		glVertex3d( point.x, point.y, point.z );
		glColor4d( color.x, color.y, color.z, color.w );
	#elif defined TZM_PERFORMANCE
		glVertex3f( point.x, point.y, point.z );
		glColor4f( color.x, color.y, color.z, color.w );
	#else
		#warning Define either TZM_PRECISION or TZM_PERFORMANCE!
	#endif
}

/// Render vertex that has position, texture coordinates, color, and normal
/**	@param point - vertex position
		@param uv - texture coordinates
		@param color - rgba color data
		@param normal - vertex normal */
void CRenderTargetOGL::RenderVertex		( cvec3r &point, cvec2r &uv, crgba &color, cvec3r &normal ) {
	#if defined TZM_PRECISION
		glVertex3d( point.x, point.y, point.z );
		glTexCoord2d( uv.x, uv.y );
		glColor4d( color.x, color.y, color.z, color.w );
		glNormal3d( normal.x, normal.y, normal.z );
	#elif defined TZM_PERFORMANCE
		glVertex3f( point.x, point.y, point.z );
		glTexCoord2f( uv.x, uv.y );
		glColor4f( color.x, color.y, color.z, color.w );
		glNormal3f( normal.x, normal.y, normal.z );
	#else
		#warning Define either TZM_PRECISION or TZM_PERFORMANCE!
	#endif

}

/// End drawing primitives
void CRenderTargetOGL::EndPrimitive		( ) {
	glEnd( );
}

/// End using the render target. Or any render target at all. It defaults back to the back buffer
void CRenderTargetOGL::End					( ) {
	#ifndef TZM_FORBID_RENDERTARGETS
		glBindFramebufferEXT	( GL_FRAMEBUFFER_EXT, 	0 );
		glBindRenderbufferEXT( GL_RENDERBUFFER_EXT, 	0 );
	#endif
}

/// This function comes from ITexture class. Bind the render target as texture.
/**	@param stage - texture stage index */
void CRenderTargetOGL::Bind				( ui16 stage ) {
	// Set the active texture stage:
	glActiveTexture( GL_TEXTURE0 + stage );
	// And bind it:
	glBindTexture( GL_TEXTURE_2D, m_uiTextureHandleOGL );
}



